home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 16321 < prev    next >
Encoding:
Text File  |  1996-08-05  |  8.7 KB  |  223 lines

  1. Path: svnews.ubinet.ubs.com!ubszh!ian.johnston@ubs.com
  2. From: ian.johnston@ubs.com (Ian Johnston (by ubsswop))
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Would/Won't you use a garbage collector?
  5. Date: 10 Apr 1996 11:34:48 GMT
  6. Organization: UBS
  7. Distribution: world
  8. Message-ID: <4kg6co$2h3@ubszh.fh.zh.ubs.com>
  9. References: <4kamie$e4d@dfw-ixnews3.ix.netcom.com>
  10. NNTP-Posting-Host: nol2179.fh.zh.ubs.com
  11.  
  12. In article <4kamie$e4d@dfw-ixnews3.ix.netcom.com>, giuliano@ix.netcom.com(Giuliano Carlini) writes:
  13. |> I'm a long time proponent of using garbage collection in C and C++
  14. |> programs, and I'm curious:
  15. |>     - How many others are there?
  16. |>     - Why don't most C/C++ programmers use it?
  17. |> I'm particularly interested in finding out why most C/C++ don't use it.
  18. |> While I have my own theories - which I'll describe below - I'm
  19. |> interested
  20. |> in finding out more directly from those who are against it.
  21.  
  22. [...]
  23.  
  24. |> What follows is my belief for why garbage collection is so little used.
  25. |> Feel free to respond to anything I say below, but please, first respond
  26. |> to the questions above. I believe that most people don't use garbage
  27. |> collection because either they:
  28. |>     - don't know what it is
  29. |>     - don't know it can be used with C/C++.
  30. |>     - are misinformation
  31. |>     - are biased against it by the C/C++ culture
  32. |> In my experience, most C/C++ programmers either don't know what garbage
  33. |> collection is, or don't know that it can be used with C/C++. After all,
  34. |> no major C/C++ compiler includes a garbage collector. At least, as far
  35. |> as I know. I hope I'm wrong, and that someone can correct me. But even
  36. |> after, I tell them what it is, and that it can be used with C++, almost
  37. |> everyone still rejects it. 
  38. |> 
  39. |> At first, most offer technical reasons for rejecting it. Almost all are
  40. |> based on misinformation, since garbage collection is usable and
  41. |> benificial
  42. |> for the vast majority of systems.
  43.  
  44. I think the reasons you give are correct. I also agree that for many (simple)
  45. systems, garbage collection (GC) is a good idea.
  46.  
  47. I would have no objection to GC being the default for C++,
  48. provided that I could switch it off and incur *minimal penalty* by
  49. overriding the GC. That is, minimal performance penalty induced
  50. by the garbage collector, even though it is not used. A performance
  51. penalty equivalent to virtual vs non-virtual function calls would be acceptable.
  52.  
  53. Remember too, that GC in C or C++ is *hard*. C has been around
  54. for 25 years or so, and C++ for about 15; it is only relatively recently that
  55. efficient garbage collectors have appeared for C and/or C++. It is not so much
  56. that the culture set out biased against GC, but the culture has probably
  57. grown that way, for the first of the three reasons you give above.
  58.  
  59. Now, do I use GC? Not in the systems I write for a living. Here's why.
  60.  
  61. First, I write servers that are intended to run for a long time, perhaps 3 months,
  62. perhaps 6 months, perhaps a year. These servers are constantly allocating and
  63. freeing objects. To use GC, I need a collector that collects 100% of the dead
  64. objects: not 95%, not 99%, not even 99.9%. I don't know of any collector for
  65. C++ that can give this guarantee.
  66.  
  67. Let's say a server averages 100 object creations per second. In a 10 hour day,
  68. that's 3.6 million objects. Say a collector leaks 0.1% of all objects. That's
  69. 3600 objects per day. At an average of 2k per object, that's 7.3MB of memory
  70. leaked per day.
  71.  
  72. Second, I write multi-threaded programs. It's not clear to me how GC works
  73. in a multi-threaded environment. Can current collectors handle one thread
  74. allocating, and a different thread freeing? Or will the apparently dead
  75. object in the allocator thread be collected, even though it is still in use
  76. by other threads? The answer has to be "no" if GC is to work in a multi-threaded
  77. environment.
  78.  
  79. Third, in the code I write, I use a variety of helper classes to help manage
  80. memory (and other resources; see below). I don't tend to use C-style arrays
  81. (stack or heap-based). I don't tend to use raw C++ pointers. These things
  82. dramatically reduce the potential for bugs. In addition, I make frequent use
  83. of customised memory allocators to increase performance of allocating/releasing
  84. space for objects. Sometimes I use shared memory. Sometimes I use statically
  85. allocated memory. Sometimes I use heap memory.
  86.  
  87. Unfortunately, there are leaks in the C libraries I use. If a 100% reliable
  88. GC could somehow be confined to the library, that would make life easier. As it
  89. is, I have to pick and choose the C library routines I use. Sadly, some can't
  90. be avoided. This is an argument for GC, rather than against :-)
  91.  
  92. Fourth, the code I write lives in a mixed-language environment. My C++ libraries
  93. are linked with main programs written in C or Ada. While GC might survive
  94. across a C/C++ boundary, it is not clear to me that it would survive across
  95. an Ada/C++ boundary. It has been a significant effort to craft my C++
  96. libraries so that they can run reliably without relying on static
  97. constructors being called!
  98.  
  99. These are the practical reasons. There is another, major reason which is
  100. partly practical and partly philosphical.
  101.  
  102. As you point out, memory is a resource. But it is not the only resource
  103. my software uses. There are other resources that are in relatively
  104. short supply: file handles, network connections, semaphores, even threads in
  105. some cases.
  106.  
  107. I don't understand why GC should be applied only to memory. If it is important
  108. to automatically reclaim unused allocated memory, why is it not important to
  109. automatically reclaim unused file handles, or unused network connections?
  110.  
  111. An important, and extremely useful idiom, in C++, is the technique of acquiring
  112. a resource in a constructor, and releasing the resource in the destructor.
  113. I have come to use this idiom very heavily, and it has made my code much simpler,
  114. much less prone to mistakes, much more robust in the presence of exceptions, and
  115. much more maintainable.
  116.  
  117. Here's an example:
  118.  
  119. class AutoLock
  120. {
  121.     public:
  122.     AutoLock(Mutex &m)
  123.         : mtx(m)
  124.     {
  125.         mtx.lock();
  126.         }
  127.  
  128.     ~AutoLock()
  129.     {
  130.         mtx.unlock();
  131.     }
  132.  
  133.     private:
  134.     Mutex &mtx;
  135. };
  136.  
  137.  
  138. Locking and unlocking a mutex at precisely the right times is critical to
  139. maximising concurrency and robustness in multi-threaded applications. If
  140. somehow the destruction of this AutoLock were left to a GC system, I would
  141. lose control over unlocking the mutex; this would be a disaster for concurrency.
  142. I simply cannot afford to let the system decide, at some point in the future,
  143. to release the mutex.
  144.  
  145. I could of course, replace this:
  146.  
  147.  
  148. void someFunc()
  149. {
  150.     AutoLock lock(someMutex);
  151.     manipulate(someObject);
  152. }
  153.  
  154.  
  155. with this:
  156.  
  157.  
  158. void someFunc()
  159. {
  160.     someMutex.lock();
  161.  
  162.     try
  163.     {
  164.     manipulate(someObject);
  165.     }
  166.     catch(...)
  167.     {
  168.     someMutex.unlock();
  169.     throw;
  170.     }
  171.  
  172.     someMutex.unlock();
  173. }
  174.  
  175.  
  176. Having this discussion some time back on comp.lang.eiffel, people there
  177. actually proposed that this second version (written in Eiffel)
  178. was the way to go. (Eiffel, of course, doesn't even have a finalisation
  179. mechanism, so there is no way to write the first version in Eiffel anyway.
  180. At least Java has finalisation, but no guarantees when it will be called
  181. [or even whether it will be called, if I remember rightly].)
  182.  
  183. Frankly, I am not prepared to forgo the first version without some
  184. extremely convincing arguments.
  185.  
  186. If I wrote GUI programs, I could make the same arguments about windows. When
  187. I click "OK" in a dialog box, I expect the dialog box to disappear. I don't
  188. expect the dialog box to hang around on screen until the GC kicks in and
  189. reclaims the dialog box (i.e. calls its finalisation routine/destructor).
  190.  
  191. Of course, GC proponents will say that you can just call the finalisation
  192. routine explicitly, thereby closing the dialog box or releasing the mutex.
  193.  
  194. But that doesn't gain anything. If I need to do that, I might just as
  195. well delete my allocated objects explicitly.
  196.  
  197. In the worst of all possible scenarios, you might have to call finalisation
  198. routines explicitly for some objects (windows, mutexes), but not for others
  199. (allocated memory). This opens up all sorts of possibilities for resource
  200. leaks and/or errors.
  201.  
  202.  
  203. What is needed is either:
  204.  
  205. - Everything is collected, not just memory resources; the approach taken
  206.   by languages like Python, I guess Lisps, and presumably, even humble
  207.   Visual Basic. For example, how do you create and destroy windows in VB?
  208.   Isn't it enough to just DIM a window and forget about destroying it?
  209.   I think you can do this with OLE objects, anyway.
  210.  
  211. - Nothing is collected, so the programmer knows they have to manage everything
  212.   themselves; the approach taken by C++, C, and even Pascal, I suppose.
  213.  
  214. A halfway house is just a recipe for confusion, it seems to me.
  215.  
  216. To sum up:
  217.  
  218. - I'm not against the concept of automatically reclaiming resources
  219. - I am against singling out memory as a special resource
  220. - I am against collecting anything less than 100% of resources
  221.  
  222. Ian
  223.